function cat(...args) {
    const head = args[0];
    const tail = args.slice(1);

    if (head instanceof Array) {
        return head.concat(...tail);
    } else {
        return [];
    }
}

function construct(head, tail) {
    return cat([head], Array.from(tail));
}

function pick(obj, ...keys) {
    return keys.reduce((pre, cur) => {
        pre[cur] = obj[cur];
        return pre;
    }, {});
}

function project(table, keys) {
    return table.map(obj => {
        return pick(obj, ...keys);
    });
}

function omit(obj, ...keys) {
    obj = {...obj};

    keys.forEach(key => {
        delete obj[key];
    });
    return obj;
}

function truthy(x) {
    return x !== false && x != null;
}

function rename(obj, newNames) {
    const newObj = {...obj};
    Object.keys(newNames).reduce((pre, cur) => {
        if (obj[cur] != null) {
            newObj[newNames[cur]] = obj[cur];
        }

        return newObj;
    }, newObj);

    return omit(newObj, Object.keys(newNames));
}

function as(table, newNames) {
    return table.map(obj => {
        return rename(obj, newNames);
    });
}

function restrict(table, pred) {
    return table.reduce((pre, cur) => {
        if (truthy(pred(cur))) {
            pre.push(cur);
        }
        return pre;
    }, []);
}